package com.platform.common.shiro;

import com.platform.common.enums.YesOrNoEnum;
import com.platform.modules.sys.domain.SysRole;
import com.platform.modules.sys.domain.SysUser;
import com.platform.modules.sys.service.SysMenuService;
import com.platform.modules.sys.service.SysRoleService;
import com.platform.modules.sys.service.SysUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.context.annotation.Lazy;

import javax.annotation.Resource;

/**
 * @author LENOVO
 * @title: UserRealm
 * @date 2019-08-2215:40
 */
public class ShiroAuthorizingRealm extends AuthorizingRealm {

    @Lazy
    @Resource
    private SysUserService sysUserService;
    @Lazy
    @Resource
    private SysRoleService sysRoleService;
    @Lazy
    @Resource
    private SysMenuService sysMenuService;

    /**
     * 提供用户信息，返回权限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("调用了授权方法");
        SysUser sysUser = ShiroUtils.getUser();
        if (sysUser == null) {
            return null;
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 添加角色
        info.addRole(sysUser.getRoleCode());
        // 添加权限
        info.addStringPermissions(sysUser.getPermissions());
        return info;
    }

    /**
     * 身份认证/登录，验证用户是不是拥有相应的身份； 用于登陆认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 用户登录验证
        if (authenticationToken instanceof UsernamePasswordToken) {
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            SysUser sysUser = sysUserService.queryByUsername(token.getUsername());
            if (sysUser == null) {
                throw new UnknownAccountException(); // 账号不存在
            }
            // 管理员
            if (ShiroUtils.isAdmin(sysUser)) {
                sysUser.setRoleCode("super");
            } else {
                // 查询角色
                SysRole sysRole = sysRoleService.getById(sysUser.getRoleId());
                if (sysRole == null) {
                    throw new DisabledAccountException("角色不存在");
                }
                if (!YesOrNoEnum.YES.getCode().equals(sysRole.getStatus())) {
                    throw new DisabledAccountException("角色被禁用");
                }
                sysUser.setRoleCode(sysRole.getCode());
                // 查询权限
                sysUser.setPermissions(sysMenuService.queryRolePerms(sysRole.getId()));
            }
            if (!YesOrNoEnum.YES.getCode().equals(sysUser.getStatus())) {
                throw new DisabledAccountException("账号被禁用"); // 账号禁用
            }
//            ConcurrentAccessException     并发访问异常（多个用户同时登录时抛出）
//            UnknownAccountException      未知的账号
//            ExcessiveAttemptsException    认证次数超过限制
//            DisabledAccountException       禁用的账号
//            LockedAccountException         账号被锁定
//            pportedTokenException            使用了不支持的Token
            /**
             * 自动验证账号 和 密码
             */
            return new SimpleAuthenticationInfo(sysUser, sysUser.getPassword(), ByteSource.Util.bytes(sysUser.getSalt()), this.getName());
        }
        return null;
    }

    @Override
    public boolean isPermitted(PrincipalCollection principals, String permission) {
        return ShiroUtils.isAdmin(ShiroUtils.getUser()) || super.isPermitted(principals, permission);
    }

    public static final String md5(String password, String salt) {
        //加密方式
        String hashAlgorithmName = "MD5";
        //盐：为了即使相同的密码不同的盐加密后的结果也不同
        ByteSource byteSalt = ByteSource.Util.bytes(salt);
        //密码
        Object source = password;
        //加密次数
        int hashIterations = 1;
        SimpleHash result = new SimpleHash(hashAlgorithmName, source, byteSalt, hashIterations);
        return result.toString();
    }

    public static void main(String[] args) {
        String credentialsSalt = "abcd";
        System.out.println(md5("c4ca4238a0b923820dcc509a6f75849b", credentialsSalt));
    }
}
